from __future__ import absolute_import
from __future__ import print_function

import cv2
import random
import numpy as np
from sklearn import preprocessing


def resize(img, size):
    """resize"""
    img = cv2.resize(img, (size, size))
    return img

def crop_center(img):
    """crop center"""
    if img.shape[0] < img.shape[1]:
        img = img.T
    # we crop image from center
    short_egde = min(img.shape[:2])
    yy = int((img.shape[0] - short_egde) / 2)
    xx = int((img.shape[1] - short_egde) / 2)
    crop_img = img[yy: yy + short_egde, xx: xx + short_egde]
    img = crop_img
    return img

def rotation_augmentation(X, rand_angle):
    for i in range(len(X)):
        angle = random.randint(-rand_angle, rand_angle)
        for j in range(X.shape[1]):
            shape = X[i, j].shape[:2]
            center = (shape[1] / 2, shape[0] / 2)
            rotation = cv2.getRotationMatrix2D(center, angle, 1.0)
            X[i, j] = cv2.warpAffine(X[i, j], rotation, shape)
    return X


def flip_h_augmentation(X):
    for i in range(len(X)):
        if random.random() < 0.5:
            for j in range(X.shape[1]):
                X[i, j] = cv2.flip(X[i, j], 1)
    return X


def flip_v_augmentation(X):
    for i in range(len(X)):
        if random.random() < 0.5:
            for j in range(X.shape[1]):
                X[i, j] = cv2.flip(X[i, j], 0)
    return X


def shift_augmentation(X, w_range=0.1, h_range=0.1):
    size = X.shape[2:]
    for i in range(len(X)):
        h_random = np.random.rand() * h_range * 2. - h_range
        w_random = np.random.rand() * w_range * 2. - w_range
        h_shift = int(h_random * size[0])
        w_shift = int(w_random * size[1])
        translation = np.float32([[1, 0, w_shift], [0, 1, h_shift]])
        for j in range(X.shape[1]):
            X[i, j] = cv2.warpAffine(X[i, j], translation, size)
    return X


def preprocess_scale(X, scaler=None):
    """
    Apply standardisation to the data, center them around the mean and give them range from -1 to 1
    """
    if not scaler:
        scaler = preprocessing.StandardScaler()
        scaler.fit(X)
    X = scaler.transform(X)
    max_scale = preprocessing.MinMaxScaler()
    max_scale.fit(X)
    X = max_scale.transform(X)
    return X, scaler


def subtract_sequence_mean(X):
    for i in range(len(X)):
        image = X[i, :, :, :]
        mean = image.mean(axis=0)
        for j in range(len(image)):
            image[j, :, :] = image[j] - mean
            image = image - image.min(axis=0)
        X[i] = image
    X -= 128.
    X /= 128.
    return X


def princomp(A, numpc=0):
    # computing eigenvalues and eigenvectors of covariance matrix
    M = (A - np.mean(A.T, axis=1)).T  # subtract the mean (along columns)
    [latent, coeff] = np.linalg.eig(np.cov(M))
    p = np.size(coeff, axis=1)
    idx = np.argsort(latent)  # sorting the eigenvalues
    idx = idx[::-1]  # in ascending order
    # sorting eigenvectors according to the sorted eigenvalues
    coeff = coeff[:, idx]
    latent = latent[idx]  # sorting eigenvalues
    if 0 <= numpc < p:
        coeff = coeff[:, range(numpc)]  # cutting some PCs if needed
        score = np.dot(coeff.T, M)  # projection of the data in the new space
    return coeff, score, latent
